package classifieurs;

import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map.Entry;

import extraction.Categorie;
import extraction.Extraction;
import extraction.Tweet;

import tools.FrenchTokenizer;
import tools.Normalizer;

public class Binomiale_3pol extends Classification{

	public Binomiale_3pol(HashMap<String, Categorie> statParClasse) {
		super(statParClasse);
	}

	/**
	 * Maps pour ranger les parametres betas - 1 par catégorie: <mot, parametre> 
	 */
	public HashMap<String, Float> mapPos = new HashMap<String, Float>();
	public HashMap<String, Float> mapNeg = new HashMap<String, Float>();
	public HashMap<String, Float> mapNeu = new HashMap<String, Float>();

	/**
	 * comptes pour binomial
	 */
	public void modeleBinomial(){
		//<mot <nbDansPositive, nbDansNegative, nbDansNeutral, nbDansIrrelevant>>
		HashMap<String, ArrayList<Float>> mapBinomial = new HashMap<String, ArrayList<Float>>();

		ArrayList<Float> tabMapBinomial;
		HashMap<String, Integer> hashPos = positive.getMotsTweet();
		HashMap<String, Integer> hashNeg = negative.getMotsTweet();
		HashMap<String, Integer> hashNeu = neutral.getMotsTweet();

		/*Tous les mots dans mapBinomial avec le tableau correspondant*/
		for(String mot : Extraction.mots){
			tabMapBinomial = new ArrayList<Float>(3);
			if (hashPos.get(mot) == null || hashPos.get(mot) == 0){
				tabMapBinomial.add(epsilon);
			}
			else{
				tabMapBinomial.add((float)hashPos.get(mot));
			}
			if (hashNeg.get(mot) == null || hashNeg.get(mot) == 0){
				tabMapBinomial.add(epsilon);
			}
			else{
				tabMapBinomial.add((float)hashNeg.get(mot));

			}
			if (hashNeu.get(mot) == null || hashNeu.get(mot) == 0){
				tabMapBinomial.add(epsilon);
			}
			else{
				tabMapBinomial.add((float)hashNeu.get(mot));
			}

			mapBinomial.put(mot, tabMapBinomial);
		}
		/**/


		Float resPos;
		Float resNeg;
		Float resNeu;

		for (Entry<String, ArrayList<Float>> entry : mapBinomial.entrySet()){
			//nbr docs contenant ce mot (dans la classe) sur nb tot docs dans classe
			resPos = entry.getValue().get(0)/ positive.getListeTweet().size();
			resNeg = entry.getValue().get(1)/ negative.getListeTweet().size();
			resNeu = entry.getValue().get(2)/ neutral.getListeTweet().size();
			mapPos.put(entry.getKey(), resPos );
			mapNeg.put(entry.getKey(), resNeg );
			mapNeu.put(entry.getKey(), resNeu );

		}
	}

	/**
	 * découpe fichier en 10 parties
	 * 1 = test, 9=apprentissage
	 * Répétition 10 fois en changeant bloc test
	 */
	public float validationCroisee(){
		ArrayList<Tweet> listeTweet = test_positive.getListeTweet();
		listeTweet.addAll(test_negative.getListeTweet());
		listeTweet.addAll(test_neutral.getListeTweet());
		int ok=0;
		int nonok=0;
		for (Tweet t : listeTweet){
			//System.out.println("tweet choisi : "+t.getSentiment()+" --> " +t.getTweetText());
			float vraisPos = calculVraisemblanceBinomial(t, mapPos);
			float vraisNeg = calculVraisemblanceBinomial(t, mapNeg);
			float vraisNeu = calculVraisemblanceBinomial(t, mapNeu);
			float max;
			max = (vraisNeg > vraisPos) ? vraisNeg : vraisPos;
			max = (vraisNeu > max) ? vraisNeu : max;

			String max_string = null;
			if (max==vraisPos) max_string = "positive";
			else if (max==vraisNeg) max_string = "negative";
			else if (max==vraisNeu) max_string = "neutral";


			if(t.getSentiment().equals("test_"+max_string)){
				ok++;
			}
			else{
				nonok++;
			}

		}
		System.out.println("ok="+ok+" et nonok="+nonok+" --> pourcentage nonok : "+ ((float)nonok/(ok+nonok)));
		return ((float)nonok/(ok+nonok));

	}

	/**
	 * decide si tweet relevant ou irrelevant
	 * @param file : fichier de sortie
	 */
	public void decision(String file){
		ArrayList<Tweet> listeTweet = test_polarite.getListeTweet();
		FileWriter fw;
		try {
			fw = new FileWriter(file);
		for (Tweet t : listeTweet){
			float vraisPos = calculVraisemblanceBinomial(t, mapPos);
			float vraisNeg = calculVraisemblanceBinomial(t, mapNeg);
			float vraisNeu = calculVraisemblanceBinomial(t, mapNeu);
			float max;

			max = (vraisNeg > vraisPos) ? vraisNeg : vraisPos;
			max = (vraisNeu > max) ? vraisNeu : max;

			String max_string = null;
			if (max==vraisPos) max_string = "positive";
			else if (max==vraisNeg) max_string = "negative";
			else if (max==vraisNeu) max_string = "neutral";

			if (t.getSentiment().equals("irrelevant")){
				//System.out.println("tweet : "+t.getTweetText()+" + polarite : "+t.getSentiment());
				fw.write("\"irrelevant\"\n");
			}
			else {
				//System.out.println("tweet : "+t.getTweetText()+" + polarite : "+max_string);
				fw.write("\""+max_string+"\"\n");
			}
		}
		fw.close();
	}
	catch (IOException e) {
		e.printStackTrace();
	}
	}


	/**
	 * decide si tweet relevant ou irrelevant
	 * @return map complete valeurs pour matrice de confusion
	 */
	public HashMap<String, HashMap<String, Integer>> decisionPolarite(){
		ArrayList<Tweet> listeTweet = test_positive.getListeTweet();
		listeTweet.addAll(test_negative.getListeTweet());
		listeTweet.addAll(test_neutral.getListeTweet());
		listeTweet.addAll(test_irrelevant.getListeTweet());
		int ok=0, nonok = 0;
		HashMap<String, Integer> err_positive = new HashMap<String, Integer>();
		HashMap<String, Integer> err_negative = new HashMap<String, Integer>();
		HashMap<String, Integer> err_neutral = new HashMap<String, Integer>();
		HashMap<String, Integer> err_irrelevant = new HashMap<String, Integer>();

		for (Tweet t : listeTweet){
			float vraisPos = calculVraisemblanceBinomial(t, mapPos);
			float vraisNeg = calculVraisemblanceBinomial(t, mapNeg);
			float vraisNeu = calculVraisemblanceBinomial(t, mapNeu);
			float max;

			max = (vraisNeg > vraisPos) ? vraisNeg : vraisPos;
			max = (vraisNeu > max) ? vraisNeu : max;

			String max_string = null;
			if (max==vraisPos) max_string = "test_positive";
			else if (max==vraisNeg) max_string = "test_negative";
			else if (max==vraisNeu) max_string = "test_neutral";

			//si moi j'ai trouvé que cetait irrelevant
			if (t.getSentiment_test().equals("irrelevant")){
				if(t.getSentiment().equals("test_irrelevant")){
					ok++;
				}
				else {
					nonok++;
				}
			}
			else{ //si j'ai trouvé que cetait relevant
				if(t.getSentiment().equals(max_string)){
					ok++;
				}
				else {
					//System.err.println("nonok");
					nonok++;
				}
			}


			if (t.getSentiment_test().equals("irrelevant")){
				if (err_irrelevant.get(t.getSentiment()) == null)
					err_irrelevant.put(t.getSentiment(), 1);
				else
					err_irrelevant.put(t.getSentiment(), err_irrelevant.get(t.getSentiment())+1);
			}
			else {
				if (max_string.contains("positive")){
					if (err_positive.get(t.getSentiment()) == null)
						err_positive.put(t.getSentiment(), 1);
					else 
						err_positive.put(t.getSentiment(), err_positive.get(t.getSentiment())+1);
				}
				else if (max_string.contains("negative")){
					if (err_negative.get(t.getSentiment()) == null)
						err_negative.put(t.getSentiment(), 1);
					else
						err_negative.put(t.getSentiment(), err_negative.get(t.getSentiment())+1);
				}
				else if (max_string.contains("neutral")){
					if (err_neutral.get(t.getSentiment()) == null)
						err_neutral.put(t.getSentiment(), 1);
					else
						err_neutral.put(t.getSentiment(), err_neutral.get(t.getSentiment())+1);
				}
			}

			
		}
		System.out.println("ok="+ok+" et nonok="+nonok+" --> pourcentage nonok : "+ ((float)nonok/(ok+nonok)));
		System.out.println("erreurs matrice : ");
		System.out.println("positive : "+err_positive);
		System.out.println("negative : "+err_negative);
		System.out.println("neutral : "+err_neutral);
		System.out.println("irrelevant : "+err_irrelevant);
		HashMap<String, HashMap<String, Integer>> mapTot = new HashMap<String, HashMap<String,Integer>>();
		mapTot.put("pos", err_positive);
		mapTot.put("neg", err_negative);
		mapTot.put("neu", err_neutral);
		mapTot.put("irr", err_irrelevant);

		//return (float)nonok/(ok+nonok);
		return mapTot;
	}


	/**
	 * Calcul vraisemblance pour 1 doc
	 * @param t : tweet  considéré
	 * @param mapCategorie : liste des mots du dico pour cette classe avec leurs parametres respectifs
	 * @return inférence : <0, plus elle est proche de 0, plus le Tweet est proche de la catégorie concernée
	 */
	public float calculVraisemblanceBinomial (Tweet t, HashMap<String, Float> mapCategorie){
		float vraisemblance = 0;
		ArrayList<String> tabMotsDoc = 	t.getMotsTweetText();
		//parcour map dico
		for (Entry<String, Float> entry : mapCategorie.entrySet()){
			//mot présent dans doc ?
			if (tabMotsDoc.contains(entry.getKey())){
				//vraisemblance 
				vraisemblance += Math.log(entry.getValue());
			}
			else
				vraisemblance += Math.log(1-entry.getValue());
		}
		return vraisemblance;
	}

}
